home *** CD-ROM | disk | FTP | other *** search
/ PC World 2003 January / PCWorld_2003-01_cd.bin / Software / Vyzkuste / rychlokurz / httrack.exe / {app} / src / htscache.c < prev    next >
C/C++ Source or Header  |  2002-11-17  |  30KB  |  918 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: httrack.c subroutines:                                 */
  34. /*       cache system (index and stores files in cache)         */
  35. /* Author: Xavier Roche                                         */
  36. /* ------------------------------------------------------------ */
  37.  
  38. #include "htscache.h"
  39.  
  40. /* specific definitions */
  41. #include "htsbase.h"
  42. #include "htsbasenet.h"
  43. #include "htsmd5.h"
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47.  
  48. #include "htsnostatic.h"
  49. /* END specific definitions */
  50.  
  51. #undef test_flush
  52. #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->errlog); }
  53.  
  54. // routines de mise en cache
  55.  
  56. /*
  57.   VERSION 1.0 :
  58.   -----------
  59.  
  60. .ndx file
  61.  file with data
  62.    <string>(date/time) [ <string>(hostname+filename) (datfile_position_ascii) ] * number_of_links
  63.  file without data
  64.    <string>(date/time) [ <string>(hostname+filename) (-datfile_position_ascii) ] * number_of_links
  65.  
  66. .dat file
  67.  [ file ] * 
  68. with
  69.   file= (with data)
  70.    [ bytes ] * sizeof(htsblk header) [ bytes ] * n(length of file given in htsblk header)
  71.  file= (without data)
  72.    [ bytes ] * sizeof(htsblk header)
  73. with
  74.  <string>(name) = <length in ascii>+<lf>+<data>
  75.  
  76.  
  77.   VERSION 1.1/1.2 :
  78.   ---------------
  79.  
  80. .ndx file
  81.  file with data
  82.    <string>("CACHE-1.1") <string>(date/time) [ <string>(hostname+filename) (datfile_position_ascii) ] * number_of_links
  83.  file without data
  84.    <string>("CACHE-1.1") <string>(date/time) [ <string>(hostname+filename) (-datfile_position_ascii) ] * number_of_links
  85.  
  86. .dat file
  87.    <string>("CACHE-1.1") [ [Header_1.1] [bytes] * n(length of file given in header) ] *
  88. with
  89.  Header_1.1=
  90.    <int>(statuscode)
  91.    <int>(size)
  92.    <string>(msg)
  93.    <string>(contenttype)
  94.    <string>(last-modified)
  95.    <string>(Etag)
  96.    [<string>"SD" <string>(supplemental data)]
  97.    [<string>"SD" <string>(supplemental data)]
  98.    ...
  99.    <string>"HTS" (end of header)
  100.    <int>(number of bytes of data) (0 if no data written)
  101. */
  102.  
  103. // Nouveau: si != text/html ne stocke que la taille
  104.  
  105.  
  106. void cache_mayadd(httrackp* opt,cache_back* cache,htsblk* r,char* url_adr,char* url_fil,char* url_save) {
  107.   if ((opt->debug>0) && (opt->log!=NULL)) {
  108.     fspc(opt->log,"debug"); fprintf(opt->log,"File checked by cache: %s"LF,url_adr);
  109.   }            
  110.   // ---stockage en cache---
  111.   // stocker dans le cache?
  112.   if (opt->cache) {
  113.     if (cache->dat!=NULL) {
  114.       // c'est le seul endroit ou l'on ajoute des elements dans le cache (fichier entier ou header)
  115.       // on stocke tout fichier "ok", mais Θgalement les rΘponses 404,301,302...
  116.       if ((r->statuscode==200)         /* stocker rΘponse standard, plus */
  117.         || (r->statuscode==204)     /* no content */
  118.         || (r->statuscode==301)     /* moved perm */
  119.         || (r->statuscode==302)     /* moved temp */
  120.         || (r->statuscode==303)     /* moved temp */
  121.         || (r->statuscode==307)     /* moved temp */
  122.         || (r->statuscode==401)     /* authorization */
  123.         || (r->statuscode==403)     /* unauthorized */
  124.         || (r->statuscode==404)     /* not found */
  125.         || (r->statuscode==410)     /* gone */
  126.         )
  127.       {        /* ne pas stocker si la page gΘnΘrΘe est une erreur */
  128.         if (!r->is_file) {
  129.           // stocker fichiers (et robots.txt)
  130.           if ( (strnotempty(url_save)) || (strcmp(url_fil,"/robots.txt")==0)) {
  131.             // ajouter le fichier au cache
  132.             cache_add(*r,url_adr,url_fil,url_save,cache->ndx,cache->dat,opt->all_in_cache);
  133.           }
  134.         }
  135.       }
  136.     }
  137.   }
  138.   // ---fin stockage en cache---
  139. }
  140.  
  141.  
  142. /* Ajout d'un fichier en cache */
  143. void cache_add(htsblk r,char* url_adr,char* url_fil,char* url_save,FILE* cache_ndx,FILE* cache_dat,int all_in_cache) {
  144.   int pos;
  145.   char s[256];
  146.   char buff[HTS_URLMAXSIZE*4];
  147.   int ok=1;
  148.   int dataincache=0;    // donnΘe en cache?
  149.   /*char digest[32+2];*/
  150.   /*digest[0]='\0';*/
  151.  
  152.   // Longueur url_save==0?
  153.   if ( (strnotempty(url_save)==0) ) {
  154.     if (strcmp(url_fil,"/robots.txt")==0)        // robots.txt
  155.       dataincache=1;
  156.     else
  157.       return;   // erreur (sauf robots.txt)
  158.   }
  159.  
  160.   if (r.size <= 0)   // taille <= 0 
  161.     return;          // refusΘ..
  162.  
  163.   // Mettre les *donΘes* en cache ?
  164.   if (is_hypertext_mime(r.contenttype))    // html, mise en cache des donnΘes et 
  165.     dataincache=1;                               // pas uniquement de l'en tΩte
  166.   else if (all_in_cache)
  167.     dataincache=1;                               // forcer tout en cache
  168.  
  169.   /* calcul md5 ? */
  170.   /*
  171.   if (is_hypertext_mime(r.contenttype)) {    // html, calcul MD5
  172.     if (r.adr) {
  173.       domd5mem(r.adr,r.size,digest,1);
  174.     }
  175.   }*/
  176.  
  177.   // Position
  178.   fflush(cache_dat); fflush(cache_ndx);
  179.   pos=ftell(cache_dat);
  180.   // Θcrire pointeur seek, adresse, fichier
  181.   if (dataincache)   // patcher
  182.     sprintf(s,"%d\n",pos);    // ecrire tel que (eh oui Θvite les \0..)
  183.   else
  184.     sprintf(s,"%d\n",-pos);   // ecrire tel que (eh oui Θvite les \0..)
  185.  
  186.   // data
  187.   // Θcrire donnΘes en-tΩte, donnΘes fichier
  188.   /*if (!dataincache) {   // patcher
  189.     r.size=-r.size;  // nΘgatif
  190.   }*/
  191.  
  192.   // Construction header
  193.   ok=0;
  194.   if (cache_wint(cache_dat,r.statuscode)!=-1)       // statuscode
  195.   if (cache_wLLint(cache_dat,r.size)!=-1)           // size
  196.   if (cache_wstr(cache_dat,r.msg)!=-1)              // msg
  197.   if (cache_wstr(cache_dat,r.contenttype)!=-1)      // contenttype
  198.   if (cache_wstr(cache_dat,r.lastmodified)!=-1)     // last-modified
  199.   if (cache_wstr(cache_dat,r.etag)!=-1)             // Etag
  200.   if (cache_wstr(cache_dat,(r.location!=NULL)?r.location:"")!=-1)         // 'location' pour moved
  201.   if (cache_wstr(cache_dat,r.cdispo)!=-1)           // Content-disposition
  202.   if (cache_wstr(cache_dat,"HTS")!=-1)              // end of header
  203.     ok=1;       /* ok */
  204.   // Fin construction header
  205.  
  206.   /*if ((int) fwrite((char*) &r,1,sizeof(htsblk),cache_dat) == sizeof(htsblk)) {*/
  207.   if (ok) {
  208.     if (dataincache) {    // mise en cache?
  209.       if (!r.adr) {       /* taille nulle (parfois en cas de 301 */
  210.         if (cache_wLLint(cache_dat,0)==-1)          /* 0 bytes */
  211.           ok=0;
  212.       } else if (r.is_write==0) {  // en mΘmoire, recopie directe
  213.         if (cache_wLLint(cache_dat,r.size)!=-1) {
  214.           if (r.size>0) {   // taille>0
  215.             if ((INTsys) fwrite(r.adr,1,(INTsys)r.size,cache_dat)!=r.size)
  216.               ok=0;
  217.           } else    // taille=0, ne rien Θcrire
  218.             ok=0;
  219.         } else
  220.           ok=0;
  221.       } else {  // recopier fichier dans cache
  222.         FILE* fp;
  223.         // On recopie le fichier..
  224.         LLint file_size=fsize(fconv(url_save));
  225.         if (file_size>=0) {
  226.           if (cache_wLLint(cache_dat,file_size)!=-1) {
  227.             fp=fopen(fconv(url_save),"rb");
  228.             if (fp!=NULL) {
  229.               char buff[32768];
  230.               int nl;
  231.               do {
  232.                 nl=fread(buff,1,32768,fp);
  233.                 if (nl>0) { 
  234.                   if ((INTsys) fwrite(buff,1,(INTsys)nl,cache_dat)!=nl) {  // erreur
  235.                     nl=-1;
  236.                     ok=0;
  237.                   }
  238.                 }
  239.               } while(nl>0);
  240.               fclose(fp);
  241.             } else ok=0;
  242.           } else ok=0;
  243.         } else ok=0;
  244.       }
  245.     } else {
  246.       if (cache_wLLint(cache_dat,0)==-1)          /* 0 bytes */
  247.         ok=0;
  248.     }
  249.   } else ok=0;
  250.   /*if (!dataincache) {   // dΘpatcher
  251.     r.size=-r.size;
  252.   }*/
  253.  
  254.   // index
  255.   // adresse+cr+fichier+cr
  256.   if (ok) {
  257.     buff[0]='\0'; strcatbuff(buff,url_adr); strcatbuff(buff,"\n"); strcatbuff(buff,url_fil); strcatbuff(buff,"\n");
  258.     cache_wstr(cache_ndx,buff);
  259.     fwrite(s,1,strlen(s),cache_ndx);
  260.   }  // si ok=0 on a peut Ωtre Θcrit des donnΘes pour rien mais on s'en tape
  261.   
  262.   // en cas de plantage, on aura au moins le cache!
  263.   fflush(cache_dat); fflush(cache_ndx);
  264. }
  265.  
  266.  
  267. // lecture d'un fichier dans le cache
  268. // si save==null alors test unqiquement
  269. htsblk cache_read(httrackp* opt,cache_back* cache,char* adr,char* fil,char* save) {
  270. #if HTS_FAST_CACHE
  271.   long int hash_pos;
  272.   int hash_pos_return;
  273. #else
  274.   char* a;
  275. #endif
  276.   char buff[HTS_URLMAXSIZE*2];
  277.   char location[HTS_URLMAXSIZE*2];
  278.   htsblk r;
  279.   int ok=0;
  280.   int header_only=0;
  281.  
  282.   memset(&r, 0, sizeof(htsblk)); r.soc=INVALID_SOCKET; strcpybuff(location,""); r.location=location;
  283. #if HTS_FAST_CACHE
  284.   strcpybuff(buff,adr); strcatbuff(buff,fil);
  285.   hash_pos_return=inthash_read((inthash)cache->hashtable,buff,(long int*)&hash_pos);
  286. #else
  287.   buff[0]='\0'; strcatbuff(buff,"\n"); strcatbuff(buff,adr); strcatbuff(buff,"\n"); strcatbuff(buff,fil); strcatbuff(buff,"\n");
  288.   if (cache->use)
  289.     a=strstr(cache->use,buff);
  290.   else
  291.     a=NULL;       // forcer erreur
  292. #endif
  293.  
  294.   /* avoid errors on data entries */
  295.   if (adr[0] == '/' && adr[1] == '/' && adr[2] == '[') {
  296. #if HTS_FAST_CACHE
  297.     hash_pos_return = 0;
  298. #else
  299.     a = NULL;
  300. #endif
  301.   }
  302.  
  303.   // en cas de succΦs
  304. #if HTS_FAST_CACHE
  305.   if (hash_pos_return) {
  306. #else
  307.   if (a!=NULL) {  // OK existe en cache!
  308. #endif
  309.     int pos;
  310. #if DEBUGCA
  311.     fprintf(stdout,"..cache: %s%s at ",adr,fil);
  312. #endif
  313.     
  314. #if HTS_FAST_CACHE
  315.     pos=hash_pos;     /* simply */
  316. #else
  317.     a+=strlen(buff);
  318.     sscanf(a,"%d",&pos);    // lire position
  319. #endif
  320. #if DEBUGCA
  321.     printf("%d\n",pos);
  322. #endif
  323.  
  324.     fflush(cache->olddat); 
  325.     if (fseek(cache->olddat,((pos>0)?pos:(-pos)),SEEK_SET) == 0) {
  326.       /* Importer cache1.0 */
  327.       if (cache->version==0) {
  328.         OLD_htsblk old_r;
  329.         if (fread((char*) &old_r,1,sizeof(old_r),cache->olddat)==sizeof(old_r)) { // lire tout (y compris statuscode etc)
  330.           r.statuscode=old_r.statuscode;
  331.           r.size=old_r.size;        // taille fichier
  332.           strcpybuff(r.msg,old_r.msg);
  333.           strcpybuff(r.contenttype,old_r.contenttype);
  334.           ok=1;     /* import  ok */
  335.         }
  336.       /* */
  337.       /* Cache 1.1 */
  338.       } else {
  339.         char check[256];
  340.         LLint size_read;
  341.         check[0]='\0';
  342.         //
  343.         cache_rint(cache->olddat,&r.statuscode);
  344.         cache_rLLint(cache->olddat,&r.size);
  345.         cache_rstr(cache->olddat,r.msg);
  346.         cache_rstr(cache->olddat,r.contenttype);
  347.         cache_rstr(cache->olddat,r.lastmodified);
  348.         cache_rstr(cache->olddat,r.etag);
  349.         cache_rstr(cache->olddat,r.location);
  350.         if (cache->version >= 2)
  351.           cache_rstr(cache->olddat,r.cdispo);
  352.         //
  353.         cache_rstr(cache->olddat,check);
  354.         if (strcmp(check,"HTS")==0) {           /* intΘgritΘ OK */
  355.           ok=1;
  356.         }
  357.         cache_rLLint(cache->olddat,&size_read);       /* lire size pour Ωtre s√r de la taille dΘclarΘe (rΘΘcrire) */
  358.         if (size_read>0) {                         /* si inscrite ici */
  359.           r.size=size_read;
  360.         } else {                              /* pas de donnΘes directement dans le cache, fichier prΘsent? */
  361.           if (r.statuscode!=200)
  362.             header_only=1;          /* que l'en tΩte ici! */
  363.         }
  364.       }
  365.  
  366.       /* Remplir certains champs */
  367.       r.totalsize=r.size;
  368.  
  369.       // lecture du header (y compris le statuscode)
  370.       /*if (fread((char*) &r,1,sizeof(htsblk),cache->olddat)==sizeof(htsblk)) { // lire tout (y compris statuscode etc)*/
  371.       if (ok) {
  372.         // sΘcuritΘ
  373.         r.adr=NULL;
  374.         r.out=NULL;
  375.         ////r.location=NULL;  non, fixΘe lors des 301 ou 302
  376.         r.fp=NULL;
  377.         
  378.         if ( (r.statuscode>=0) && (r.statuscode<=999)
  379.           && (r.notmodified>=0)  && (r.notmodified<=9) ) {   // petite vΘrif intΘgritΘ
  380.           if ((save) && (!header_only) ) {     /* ne pas lire uniquement header */
  381.             //int to_file=0;
  382.             
  383.             r.adr=NULL; r.soc=INVALID_SOCKET; 
  384.             // // r.location=NULL;
  385.             
  386. #if HTS_DIRECTDISK
  387.             // Court-circuit:
  388.             // Peut-on stocker le fichier directement sur disque?
  389.             if ((r.statuscode==200) && (!is_hypertext_mime(r.contenttype)) && (strnotempty(save))) {    // pas HTML, Θcrire sur disk directement
  390.               int ok=0;
  391.               
  392.               r.is_write=1;    // Θcrire
  393.               if (fexist(antislash(save))) {  // un fichier existe dΘja
  394.                 //if (fsize(antislash(save))==r.size) {  // mΩme taille -- NON tant pis (taille mal declaree)
  395.                 ok=1;    // plus rien α faire
  396.                 filenote(save,NULL);        // noter comme connu
  397.                 //}
  398.               }
  399.               
  400.               if ((pos<0) && (!ok)) { // Pas de donnΘe en cache et fichier introuvable : erreur!
  401.                 if (opt->norecatch) {
  402.                   filecreateempty(save);
  403.                   //
  404.                   r.statuscode=-1;
  405.                   strcpybuff(r.msg,"File deleted by user not recaught");
  406.                   ok=1;     // ne pas rΘcupΘrer (et pas d'erreur)
  407.                 } else {
  408.                   r.statuscode=-1;
  409.                   strcpybuff(r.msg,"Previous cache file not found");
  410.                   ok=1;    // ne pas rΘcupΘrer
  411.                 }
  412.               }
  413.               
  414.               if (!ok) {  
  415.                 r.out=filecreate(save);
  416. #if HDEBUG
  417.                 printf("direct-disk: %s\n",save);
  418. #endif
  419.                 if (r.out!=NULL) {
  420.                   char buff[32768+4];
  421.                   LLint nl;
  422.                   LLint size;
  423.                   size=r.size;
  424.                   do {
  425.                     nl=fread(buff,1,(INTsys) minimum(size,32768),cache->olddat);
  426.                     if (nl>0) {
  427.                       size-=nl; 
  428.                       if ((INTsys) fwrite(buff,1,(INTsys)nl,r.out)!=nl) {  // erreur
  429.                         r.statuscode=-1;
  430.                         strcpybuff(r.msg,"Cache Read Error : Read To Disk");
  431.                       }
  432.                     }
  433.                   } while((nl>0) && (size>0) && (r.statuscode!=-1));
  434.                   
  435.                   fclose(r.out);
  436.                   r.out=NULL;
  437. #if HTS_WIN==0
  438.                   chmod(save,HTS_ACCESS_FILE);      
  439. #endif          
  440.                   usercommand(0,NULL,antislash(save));
  441.                 } else {
  442.                   r.statuscode=-1;
  443.                   strcpybuff(r.msg,"Cache Write Error : Unable to Create File");
  444.                   //printf("%s\n",save);
  445.                 }
  446.               }
  447.               
  448.             } else
  449. #endif
  450.             { // lire en mΘmoire
  451.               
  452.               if (pos<0) { // Pas de donnΘe en cache, bizarre car html!!!
  453.                 r.statuscode=-1;
  454.                 strcpybuff(r.msg,"Previous cache file not found (2)");
  455.               } else {
  456.                 // lire fichier (d'un coup)
  457.                 r.adr=(char*) malloct((INTsys)r.size+4);
  458.                 if (r.adr!=NULL) {
  459.                   if ((INTsys) fread(r.adr,1,(INTsys)r.size,cache->olddat)!=r.size) {  // erreur
  460.                     freet(r.adr);
  461.                     r.adr=NULL;
  462.                     r.statuscode=-1;
  463.                     strcpybuff(r.msg,"Cache Read Error : Read Data");
  464.                   } else
  465.                     *(r.adr+r.size)='\0';
  466.                   //printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
  467.                 } else {  // erreur
  468.                   r.statuscode=-1;
  469.                   strcpybuff(r.msg,"Cache Memory Error");
  470.                 }
  471.               }
  472.             }
  473.           }    // si save==null, ne rien charger (juste en tΩte)
  474.         } else {
  475. #if DEBUGCA
  476.           printf("Cache Read Error : Bad Data");
  477. #endif
  478.           r.statuscode=-1;
  479.           strcpybuff(r.msg,"Cache Read Error : Bad Data");
  480.         }
  481.       } else {  // erreur
  482. #if DEBUGCA
  483.         printf("Cache Read Error : Read Header");
  484. #endif
  485.         r.statuscode=-1;
  486.         strcpybuff(r.msg,"Cache Read Error : Read Header");
  487.       }
  488.     } else {
  489. #if DEBUGCA
  490.       printf("Cache Read Error : Seek Failed");
  491. #endif
  492.       r.statuscode=-1;
  493.       strcpybuff(r.msg,"Cache Read Error : Seek Failed");
  494.     }
  495.   } else {
  496. #if DEBUGCA
  497.     printf("File Cache Not Found");
  498. #endif
  499.     r.statuscode=-1;
  500.     strcpybuff(r.msg,"File Cache Not Found");
  501.   }
  502.   return r;
  503. }
  504.  
  505. /* write (string1-string2)-data in cache */
  506. /* 0 if failed */
  507. int cache_writedata(FILE* cache_ndx,FILE* cache_dat,char* str1,char* str2,char* outbuff,int len) {
  508.   if (cache_dat) {
  509.     char buff[HTS_URLMAXSIZE*4];
  510.     char s[256];
  511.     int pos;
  512.     fflush(cache_dat); fflush(cache_ndx);
  513.     pos=ftell(cache_dat);
  514.     /* first write data */
  515.     if (cache_wint(cache_dat,len)!=-1) {       // length
  516.       if ((INTsys) fwrite(outbuff,1,(INTsys)len,cache_dat) == (INTsys) len) {   // data
  517.         /* then write index */
  518.         sprintf(s,"%d\n",pos);
  519.         buff[0]='\0'; strcatbuff(buff,str1); strcatbuff(buff,"\n"); strcatbuff(buff,str2); strcatbuff(buff,"\n");
  520.         cache_wstr(cache_ndx,buff);
  521.         if (fwrite(s,1,strlen(s),cache_ndx) == strlen(s)) {
  522.           fflush(cache_dat); fflush(cache_ndx);
  523.           return 1;
  524.         }
  525.       }
  526.     }
  527.   }
  528.   return 0;
  529. }
  530.  
  531. /* read the data corresponding to (string1-string2) in cache */
  532. /* 0 if failed */
  533. int cache_readdata(cache_back* cache,char* str1,char* str2,char** inbuff,int* inlen) {
  534. #if HTS_FAST_CACHE
  535.   if (cache->hashtable) {
  536.     char buff[HTS_URLMAXSIZE*4];
  537.     long int pos;
  538.     strcpybuff(buff,str1); strcatbuff(buff,str2);
  539.     if (inthash_read((inthash)cache->hashtable,buff,(long int*)&pos)) {
  540.       if (fseek(cache->olddat,((pos>0)?pos:(-pos)),SEEK_SET) == 0) {
  541.         int len;
  542.         cache_rint(cache->olddat,&len);
  543.         if (len>0) {
  544.           char* mem_buff=(char*)malloct(len+4);    /* Plus byte 0 */
  545.           if (mem_buff) {
  546.             if ((int)fread(mem_buff,1,len,cache->olddat)==len) { // lire tout (y compris statuscode etc)*/
  547.               *inbuff=mem_buff;
  548.               *inlen=len;
  549.               return 1;
  550.             } else
  551.               freet(mem_buff);
  552.           }
  553.         }
  554.       }
  555.     }
  556.   }
  557. #endif
  558.   *inbuff=NULL;
  559.   *inlen=0;
  560.   return 0;
  561. }
  562.  
  563. // renvoyer uniquement en tΩte, ou NULL si erreur
  564. htsblk* cache_header(httrackp* opt,cache_back* cache,char* adr,char* fil) {
  565.   htsblk* r;
  566.   NOSTATIC_RESERVE(r, htsblk, 1);
  567.   *r=cache_read(opt,cache,adr,fil,NULL);              // test uniquement
  568.   if (r->statuscode != -1)
  569.     return r;
  570.   else
  571.     return NULL;
  572. }
  573.  
  574.  
  575. // Initialisation du cache: crΘer nouveau, renomer ancien, charger..
  576. void cache_init(cache_back* cache,httrackp* opt) {
  577.   // ---
  578.   // utilisation du cache: renommer ancien Θventuel et charger index
  579.   if (opt->cache) {
  580. #if DEBUGCA
  581.     printf("cache init: ");
  582. #endif
  583.     if (!cache->ro) {
  584. #if HTS_WIN
  585.       mkdir(fconcat(opt->path_log,"hts-cache"));
  586. #else
  587.       mkdir(fconcat(opt->path_log,"hts-cache"),HTS_PROTECT_FOLDER);
  588. #endif
  589.       if ((fexist(fconcat(opt->path_log,"hts-cache/new.dat"))) && (fexist(fconcat(opt->path_log,"hts-cache/new.ndx")))) {  // il existe dΘja un cache prΘcΘdent.. renommer
  590. #if DEBUGCA
  591.         printf("work with former cache\n");
  592. #endif
  593.         if (fexist(fconcat(opt->path_log,"hts-cache/old.dat")))
  594.           remove(fconcat(opt->path_log,"hts-cache/old.dat"));
  595.         if (fexist(fconcat(opt->path_log,"hts-cache/old.ndx")))
  596.           remove(fconcat(opt->path_log,"hts-cache/old.ndx"));
  597.         
  598.         rename(fconcat(opt->path_log,"hts-cache/new.dat"),fconcat(opt->path_log,"hts-cache/old.dat"));
  599.         rename(fconcat(opt->path_log,"hts-cache/new.ndx"),fconcat(opt->path_log,"hts-cache/old.ndx"));
  600.       } else {  // un des deux (ou les deux) fichiers cache absents: effacer l'autre Θventuel
  601. #if DEBUGCA
  602.         printf("new cache\n");
  603. #endif
  604.         if (fexist(fconcat(opt->path_log,"hts-cache/new.dat")))
  605.           remove(fconcat(opt->path_log,"hts-cache/new.dat"));
  606.         if (fexist(fconcat(opt->path_log,"hts-cache/new.ndx")))
  607.           remove(fconcat(opt->path_log,"hts-cache/new.ndx"));
  608.       }
  609.     }
  610.     
  611.     // charger index cache prΘcΘdent
  612.     if (
  613.       (
  614.       !cache->ro &&
  615.       fsize(fconcat(opt->path_log,"hts-cache/old.dat")) >=0 && fsize(fconcat(opt->path_log,"hts-cache/old.ndx")) >0
  616.       )
  617.       ||
  618.       (
  619.       cache->ro &&
  620.       fsize(fconcat(opt->path_log,"hts-cache/new.dat")) >=0 && fsize(fconcat(opt->path_log,"hts-cache/new.ndx")) > 0
  621.       )
  622.       ) {
  623.       FILE* oldndx=NULL;
  624. #if DEBUGCA
  625.       printf("..load cache\n");
  626. #endif
  627.       if (!cache->ro) {
  628.         cache->olddat=fopen(fconcat(opt->path_log,"hts-cache/old.dat"),"rb");        
  629.         oldndx=fopen(fconcat(opt->path_log,"hts-cache/old.ndx"),"rb");        
  630.       } else {
  631.         cache->olddat=fopen(fconcat(opt->path_log,"hts-cache/new.dat"),"rb");        
  632.         oldndx=fopen(fconcat(opt->path_log,"hts-cache/new.ndx"),"rb");        
  633.       }
  634.       // les deux doivent Ωtre ouvrables
  635.       if ((cache->olddat==NULL) && (oldndx!=NULL)) {
  636.         fclose(oldndx);
  637.         oldndx=NULL;
  638.       }
  639.       if ((cache->olddat!=NULL) && (oldndx==NULL)) {
  640.         fclose(cache->olddat);
  641.         cache->olddat=NULL;
  642.       }
  643.       // lire index
  644.       if (oldndx!=NULL) {
  645.         int buffl;
  646.         fclose(oldndx); oldndx=NULL;
  647.         // lire ndx, et lastmodified
  648.         if (!cache->ro) {
  649.           buffl=fsize(fconcat(opt->path_log,"hts-cache/old.ndx"));
  650.           cache->use=readfile(fconcat(opt->path_log,"hts-cache/old.ndx"));
  651.         } else {
  652.           buffl=fsize(fconcat(opt->path_log,"hts-cache/new.ndx"));
  653.           cache->use=readfile(fconcat(opt->path_log,"hts-cache/new.ndx"));
  654.         }
  655.         if (cache->use!=NULL) {
  656.           char firstline[256];
  657.           char* a=cache->use;
  658.           a+=cache_brstr(a,firstline);
  659.           if (strncmp(firstline,"CACHE-",6)==0) {       // Nouvelle version du cache
  660.             if (strncmp(firstline,"CACHE-1.",8)==0) {      // Version 1.1x
  661.               cache->version=(int)(firstline[8]-'0');           // cache 1.x
  662.               if (cache->version <= 2) {
  663.                 a+=cache_brstr(a,firstline);
  664.                 strcpybuff(cache->lastmodified,firstline);
  665.               } else {
  666.                 if (opt->errlog) {
  667.                   fspc(opt->errlog,"error"); fprintf(opt->errlog,"Cache: version 1.%d not supported, ignoring current cache"LF,cache->version);
  668.                   fflush(opt->errlog);
  669.                 }
  670.                 fclose(cache->olddat);
  671.                 cache->olddat=NULL;
  672.                 freet(cache->use);
  673.                 cache->use=NULL;
  674.               }
  675.             } else {        // non supportΘ
  676.               if (opt->errlog) {
  677.                 fspc(opt->errlog,"error"); fprintf(opt->errlog,"Cache: %s not supported, ignoring current cache"LF,firstline);
  678.                 fflush(opt->errlog);
  679.               }
  680.               fclose(cache->olddat);
  681.               cache->olddat=NULL;
  682.               freet(cache->use);
  683.               cache->use=NULL;
  684.             }
  685.             /* */
  686.           } else {              // Vieille version du cache
  687.             /* */
  688.             if (opt->log) {
  689.               fspc(opt->log,"warning"); fprintf(opt->log,"Cache: importing old cache format"LF);
  690.               fflush(opt->log);
  691.             }
  692.             cache->version=0;        // cache 1.0
  693.             strcpybuff(cache->lastmodified,firstline); 
  694.           }
  695.           opt->is_update=1;        // signaler comme update
  696.           
  697.           /* Create hash table for the cache (MUCH FASTER!) */
  698. #if HTS_FAST_CACHE
  699.           if (cache->use) {
  700.             char line[HTS_URLMAXSIZE*2];
  701.             char linepos[256];
  702.             int  pos;
  703.             while ( (a!=NULL) && (a < (cache->use+buffl) ) ) {
  704.               a=strchr(a+1,'\n');     /* start of line */
  705.               if (a) {
  706.                 a++;
  707.                 /* read "host/file" */
  708.                 a+=binput(a,line,HTS_URLMAXSIZE);
  709.                 a+=binput(a,line+strlen(line),HTS_URLMAXSIZE);
  710.                 /* read position */
  711.                 a+=binput(a,linepos,200);
  712.                 sscanf(linepos,"%d",&pos);
  713.                 inthash_add((inthash)cache->hashtable,line,pos);
  714.               }
  715.             }
  716.             /* Not needed anymore! */
  717.             freet(cache->use);
  718.             cache->use=NULL;
  719.           }
  720. #endif
  721.         }
  722.       }
  723.       }  // taille cache>0
  724.       
  725. #if DEBUGCA
  726.       printf("..create cache\n");
  727. #endif
  728.       if (!cache->ro) {
  729.         // ouvrir caches actuels
  730.         cache->dat=fopen(fconcat(opt->path_log,"hts-cache/new.dat"),"wb");        
  731.         cache->ndx=fopen(fconcat(opt->path_log,"hts-cache/new.ndx"),"wb");        
  732.         // les deux doivent Ωtre ouvrables
  733.         if ((cache->dat==NULL) && (cache->ndx!=NULL)) {
  734.           fclose(cache->ndx);
  735.           cache->ndx=NULL;
  736.         }
  737.         if ((cache->dat!=NULL) && (cache->ndx==NULL)) {
  738.           fclose(cache->dat);
  739.           cache->dat=NULL;
  740.         }
  741.         
  742.         if (cache->ndx!=NULL) {
  743.           char s[256];
  744.           
  745.           cache_wstr(cache->dat,"CACHE-1.2");
  746.           fflush(cache->dat);
  747.           cache_wstr(cache->ndx,"CACHE-1.2");
  748.           fflush(cache->ndx);
  749.           //
  750.           time_gmt_rfc822(s);   // date et heure actuelle GMT pour If-Modified-Since..
  751.           cache_wstr(cache->ndx,s);        
  752.           fflush(cache->ndx);    // un petit fflush au cas o∙
  753.           
  754.           // supprimer old.lst
  755.           if (fexist(fconcat(opt->path_log,"hts-cache/old.lst")))
  756.             remove(fconcat(opt->path_log,"hts-cache/old.lst"));
  757.           // renommer
  758.           if (fexist(fconcat(opt->path_log,"hts-cache/new.lst")))
  759.             rename(fconcat(opt->path_log,"hts-cache/new.lst"),fconcat(opt->path_log,"hts-cache/old.lst"));
  760.           // ouvrir
  761.           cache->lst=fopen(fconcat(opt->path_log,"hts-cache/new.lst"),"wb");
  762.           {
  763.             filecreate_params tmp;
  764.             strcpybuff(tmp.path,opt->path_html);    // chemin
  765.             tmp.lst=cache->lst;                 // fichier lst
  766.             filenote("",&tmp);        // initialiser filecreate
  767.           }
  768.           
  769.           // supprimer old.txt
  770.           if (fexist(fconcat(opt->path_log,"hts-cache/old.txt")))
  771.             remove(fconcat(opt->path_log,"hts-cache/old.txt"));
  772.           // renommer
  773.           if (fexist(fconcat(opt->path_log,"hts-cache/new.txt")))
  774.             rename(fconcat(opt->path_log,"hts-cache/new.txt"),fconcat(opt->path_log,"hts-cache/old.txt"));
  775.           // ouvrir
  776.           cache->txt=fopen(fconcat(opt->path_log,"hts-cache/new.txt"),"wb");
  777.           if (cache->txt) {
  778.             fprintf(cache->txt,"date\tsize'/'remotesize\tflags(request:Update,Range state:File response:Modified,Chunked,gZipped)\t");
  779.             fprintf(cache->txt,"statuscode\tstatus ('servermsg')\tMIME\tEtag|Date\tURL\tlocalfile\t(from URL)"LF);
  780.           }
  781.           
  782.           // test
  783.           // cache_writedata(cache->ndx,cache->dat,"//[TEST]//","test1","TEST PIPO",9);
  784.         }
  785.         
  786.       } else {
  787.         cache->lst = cache->dat = cache->ndx = NULL;
  788.       }
  789.       
  790.   }
  791.   
  792. }
  793.  
  794.  
  795.  
  796.  
  797. // lire un fichier.. (compatible \0)
  798. char* readfile(char* fil) {
  799.   char* adr=NULL;
  800.   int len=0;
  801.   len=fsize(fil);
  802.   if (len>0) {  // existe
  803.     FILE* fp;
  804.     fp=fopen(fconv(fil),"rb");
  805.     if (fp!=NULL) {  // n'existe pas (!)
  806.       adr=(char*) malloct(len+1);
  807.       if (adr!=NULL) {
  808.         if ((int) fread(adr,1,len,fp)!=len) {    // fichier endommagΘ ?
  809.           freet(adr);
  810.           adr=NULL;
  811.         } else
  812.           *(adr+len)='\0';
  813.       }
  814.       fclose(fp);
  815.     }
  816.   }
  817.   return adr;
  818. }
  819.  
  820. char* readfile_or(char* fil,char* defaultdata) {
  821.   char* realfile=fil;
  822.   char* ret;
  823.   if (!fexist(fil))
  824.     realfile=fconcat(hts_rootdir(NULL),fil);
  825.   ret=readfile(realfile);
  826.   if (ret)
  827.     return ret;
  828.   else {
  829.     char *adr=malloct(strlen(defaultdata)+2);
  830.     if (adr) {
  831.       strcpybuff(adr,defaultdata);
  832.       return adr;
  833.     }
  834.   }
  835.   return NULL;
  836. }
  837.  
  838. // Θcriture/lecture d'une chaεne sur un fichier
  839. // -1 : erreur, sinon 0
  840. int cache_wstr(FILE* fp,char* s) {
  841.   int i;
  842.   char buff[256+4];
  843.   i=strlen(s);
  844.   sprintf(buff,"%d\n",i);
  845.   if (fwrite(buff,1,strlen(buff),fp) != strlen(buff))
  846.     return -1;
  847.   if (i>0)
  848.   if ((int) fwrite(s,1,i,fp) != i)
  849.     return -1;
  850.   return 0;
  851. }
  852. void cache_rstr(FILE* fp,char* s) {
  853.   int i;
  854.   char buff[256+4];
  855.   linput(fp,buff,256);
  856.   sscanf(buff,"%d",&i);
  857.   if (i < 0 || i > 32768)    /* error, something nasty happened */
  858.     i=0;
  859.   if (i>0)
  860.     fread(s,1,i,fp);
  861.   *(s+i)='\0';
  862. }
  863. int cache_brstr(char* adr,char* s) {
  864.   int i;
  865.   int off;
  866.   char buff[256+4];
  867.   off=binput(adr,buff,256);
  868.   adr+=off;
  869.   sscanf(buff,"%d",&i);
  870.   if (i>0)
  871.     strncpy(s,adr,i);
  872.   *(s+i)='\0';
  873.   off+=i;
  874.   return off;
  875. }
  876. int cache_quickbrstr(char* adr,char* s) {
  877.   int i;
  878.   int off;
  879.   char buff[256+4];
  880.   off=binput(adr,buff,256);
  881.   adr+=off;
  882.   sscanf(buff,"%d",&i);
  883.   if (i>0)
  884.     strncpy(s,adr,i);
  885.   *(s+i)='\0';
  886.   off+=i;
  887.   return off;
  888. }
  889. /* idem, mais en int */
  890. int cache_brint(char* adr,int* i) {
  891.   char s[256];
  892.   int r=cache_brstr(adr,s);
  893.   if (r!=-1)
  894.     sscanf(s,"%d",i);
  895.   return r;
  896. }
  897. void cache_rint(FILE* fp,int* i) {
  898.   char s[256];
  899.   cache_rstr(fp,s);
  900.   sscanf(s,"%d",i);
  901. }
  902. int cache_wint(FILE* fp,int i) {
  903.   char s[256];
  904.   sprintf(s,"%d",(int) i);
  905.   return cache_wstr(fp,s);
  906. }
  907. void cache_rLLint(FILE* fp,LLint* i) {
  908.   char s[256];
  909.   cache_rstr(fp,s);
  910.   sscanf(s,LLintP,i);
  911. }
  912. int cache_wLLint(FILE* fp,LLint i) {
  913.   char s[256];
  914.   sprintf(s,LLintP,(LLint) i);
  915.   return cache_wstr(fp,s);
  916. }
  917. // -- cache --
  918.